package cc.verywell.pureblock.msg.nfs.map;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;

import cc.verywell.pureblock.func.node.KeyShell;
import cc.verywell.pureblock.util.unsafe.UnsafeRun;

/**
* 
* 2019年5月12日 本类作为方案储备，暂不启用;
* 
* Copyright © 2019 TanYaqiu. All rights reserved.
* @author TanYaqiu 
* @address flat 601
* @date 2019年5月5日 上午6:38:14
*/
public class MEMmapHolding implements FSmap {

	final private long capacity; 
	final private LinkedHashMap<KeyShell,HoldValue> lockmap;
	
	public MEMmapHolding(long capacity)  {
		this.capacity = capacity;
		this.lockmap = new LinkedHashMap<>((int)(capacity>>10),0.9f,true);
	}

	@Override
	public synchronized byte[] get(KeyShell key) {
		return lockmap.get(key).d;
	}
	@Override
	public synchronized boolean contain(KeyShell key) {
		return lockmap.containsKey(key);
	}
	public synchronized int contain(KeyShell key, Holding holding) {
		HoldValue h = lockmap.get(key);
		if(h==null)return -1;
		h.addHolding(holding);
		return h.d.length;
	}

	private long used;
	@Override
	public boolean put(KeyShell key, byte[] bb) {
		return put(key, bb, null);
	}
	public synchronized boolean put(KeyShell k, byte[] bb, Holding holding) {
		if(lockmap.get(k)!=null)return false;
		long s = countSize(k, bb);
		if(s>capacity)return false;
		used += s;
		if(used>capacity) {
			Iterator<Map.Entry<KeyShell,HoldValue>> it = lockmap.entrySet().iterator();
			while(it.hasNext() && used>capacity) {
				Map.Entry<KeyShell,HoldValue> entry = it.next();
				if(entry.getValue().isHolding())continue;
				used -= countSize(entry.getKey(),entry.getValue().d);
				it.remove();
			}
			if(used>capacity) {
				used -= s;
				return false;
			}
		}
		lockmap.put(k, holding==null?new HoldValue(bb):new HoldValue(bb,holding));
		return true;
	}

	@Override
	public synchronized boolean remove(KeyShell k) {
		HoldValue bb = lockmap.remove(k);
		if(bb==null)return false;
		used -= countSize(k,bb.d);
		return true;
	}
	
	protected long countSize(KeyShell key,byte[] value) {
		return 8+UnsafeRun.MemoryAddressSize*5+16*2+key.key.length+value.length;
	}
	
	public synchronized long getUsed() {
		return used;
	}
	
	
	@Override
	public synchronized String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("MEMmap files:").append(lockmap.size());
		sb.append(" used:").append(used).append("/").append(capacity);
		return sb.toString();
	}


	static private class HoldValue implements Holding{
		final public byte[] d;
		public LinkedList<Holding> h;
		public HoldValue(byte[] bb) {
			this.d = bb;
		}
		public HoldValue(byte[] bb,Holding holding) {
			this(bb);
			addHolding(holding);
		}
		@Override
		public synchronized boolean isHolding() {
			if(h==null)return false;
			Holding holding;
			while(null!=(holding=h.getFirst())) {
				if(holding.isHolding())return true;
				else h.removeFirst();
			}
			h=null;
			return false;
		}
		public synchronized void addHolding(Holding holding) {
			if(holding==null)throw new NullPointerException();
			if(h==null)h = new LinkedList<>();
			h.add(holding);
		}
	}
	
	@FunctionalInterface
	public static interface Holding{
		public boolean isHolding();
	}
	
}
